using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.Shell.Interop;
using Koda.Search;
using Koda.VisualStudio;
using EnvDTE80;
using Koda.Utils;

namespace Koda.Search.Finders
{
    public abstract class SymbolFinderBase : VsFinderBase
    {
        private DTE2 dte;
        private IVsObjectList2 objectList;

        protected abstract _LIB_LISTTYPE ListType
        {
            get;
        }

        protected abstract LIB_CATEGORY Category
        {
            get;
        }

        public SymbolFinderBase(DTE2 dte)
        {
            if (dte == null)
                throw new ArgumentNullException("dte");

            this.dte = dte;
        }

        protected override List<VsItem> Refresh()
        {
            IVsLibrary2 library = VsUtilities.GetIVsLibrary2(this.dte, VsUtilities.CSharpLibrary);

            VSOBSEARCHCRITERIA2[] searchCriteria = new VSOBSEARCHCRITERIA2[1];
            searchCriteria[0].eSrchType = VSOBSEARCHTYPE.SO_PRESTRING;
            searchCriteria[0].szName = "*";

            List<VsItem> items = new List<VsItem>();
            this.objectList = null;

            library.GetList2(
                (uint)this.ListType,
                (uint)_LIB_LISTFLAGS.LLF_USESEARCHFILTER,
                searchCriteria,
                out this.objectList);

            if (this.objectList != null)
            {
                uint count;
                this.objectList.GetItemCount(out count);
                for (uint index = 0; index < count; index++)
                {
                    uint field;
                    this.objectList.GetCategoryField2(index, (int)this.Category, out field);
                    VsItemType type = this.GetVsItemType(field);

                    object fullNameValue = null;
                    this.objectList.GetProperty(
                        index,
                        (int)_VSOBJLISTELEMPROPID.VSOBJLISTELEMPROPID_FULLNAME,
                        out fullNameValue);

                    string fullName = (string)fullNameValue;
                    string name = this.ParseName(fullName);

                    VsItem item = new VsItem(index, name, fullName, String.Empty, type);
                    items.Add(item);
                }
            }

            return items;
        }

        public override bool OpenItem(VsItem item)
        {
            if (item == null)
                throw new ArgumentNullException("item");

            if (this.objectList != null)
            {
                int canGoToSource = -1;
                this.objectList.CanGoToSource(item.Index, VSOBJGOTOSRCTYPE.GS_DEFINITION, out canGoToSource);
                if (canGoToSource == 1)
                {
                    this.objectList.GoToSource(item.Index, VSOBJGOTOSRCTYPE.GS_DEFINITION);
                    return true;
                }
            }

            return false;
        }

        protected abstract VsItemType GetVsItemType(uint value);
        protected abstract string ParseName(string fullName);

    }
}
